<!--
 * @description 组件
 * @author: 陈陈
 * @date: 2025/05/09
 * @phone: 18560000860
 * @email: 18560000860@qq.com
 * @company: 济南晨霜信息技术有限公司 /
 * @business: 承接前后端项目的开发
-->
<template>
	<form
		class="pure-form"
		:class="_classes"
		:style="_styles"
	>
		<slot></slot>
	</form>
</template>

<!-- <script>
	import commonComponentOptions from "../../config/options";
	export default {
		options: commonComponentOptions,
	};
</script> -->

<script setup>
	import { ref, computed, provide, onMounted } from "vue";
	import props from "./props";
	import Schema from "async-validator";
	import { isPlainObject } from "@/uni_modules/pure-utils";

	// -------------------------------------------------------------------------------- Refs
	// 字段单独设置的验证规则
	const _filedsRules = ref({});

	// 未验证通过的字段
	const _invalidFields = ref({});

	// -------------------------------------------------------------------------------- Props
	const _props = defineProps(props);

	// -------------------------------------------------------------------------------- Emits
	const _emits = defineEmits(["onExpose"]);

	// -------------------------------------------------------------------------------- Classes
	const _classes = computed(() => {
		const array = [];

		// 禁用表单
		if (_props.disabled) array.push("pure-form--disabled");

		// 隐藏必填符号
		if (_props.hideRequiredSymbol) array.push("pure-form--hide-required-symbol");

		return array;
	});

	// -------------------------------------------------------------------------------- Styles
	const _styles = computed(() => {
		const array = [];
		return array;
	});

	// 最终的表单验证规则 = 全局规则 + 字段单独设置的规则
	const _finalRules = computed(() => {
		return {
			..._props.rules,
			..._filedsRules.value
		};
	});

	// 更新字段的验证规则
	function updatePureFormRules(fieldName, rules) {
		if (fieldName && rules) {
			_filedsRules.value[fieldName] = rules;
		}
	}

	// 表单校验
	function validate() {
		// 清空上次验证结果
		_invalidFields.value = {};

		// 验证器
		const validator = new Schema(_finalRules.value);

		// options 验证选项
		const options = {
			first: false, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
			firstFields: true, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
			suppressWarning: true // 是否禁止无效值的内部警告
		};

		// 验证表单数据
		return new Promise((resolve, reject) => {
			validator
				.validate(_props?.model || {}, options, (errors, fields) => {
					// 验证未通过
					if (errors) {
						console.warn("表单验证未通过", errors, fields);
						showError(errors, fields);
						reject(false);
					}

					// 验证通过
					else {
						_invalidFields.value = {};
						resolve(true);
					}
				})
				.catch(() => {});
		});
	}

	// 单字段验证
	function validateField(fieldName) {
		const schema = {};
		schema[fieldName] = _finalRules.value[fieldName];

		// 验证器
		const validator = new Schema(schema);

		// options 验证选项
		const options = {
			first: false, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
			firstFields: true, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
			suppressWarning: true // 是否禁止无效值的内部警告
		};

		// 验证表单数据
		return new Promise((resolve, reject) => {
			validator
				.validate(_props?.model || {}, options, (errors, fields) => {
					// 验证未通过
					if (errors) {
						console.warn("表单字段验证未通过", errors, fields);
						showError(errors, fields);
						reject(false);
					}

					// 验证通过
					else {
						try {
							delete _invalidFields.value[fieldName];
						} catch (error) {}
						resolve(true);
					}
				})
				.catch(() => {});
		});
	}

	// 多字段验证
	function validateFields(fieldNames = []) {
		const schema = {};
		fieldNames.forEach((fieldName) => {
			schema[fieldName] = _finalRules.value[fieldName];
		});

		// 验证器
		const validator = new Schema(schema);

		// options 验证选项
		const options = {
			first: false, // 第一个未通过校验的字段发生错误就调用 callback，即不再继续校验剩余字段
			firstFields: true, // 每个字段的第一个规则发生错误就调用 callback，即不再继续校验该字段的剩余规则
			suppressWarning: true // 是否禁止无效值的内部警告
		};

		// 验证表单数据
		return new Promise((resolve, reject) => {
			validator
				.validate(_props?.model || {}, options, (errors, fields) => {
					// 验证未通过
					if (errors) {
						// 验证未通过的字段keys
						const invalidFieldKeys = Object.keys(fields);
						// 找到本次验证通过的字段
						const validFieldKeys = fieldNames.filter((fieldName) => !invalidFieldKeys.includes(fieldName));
						// 删掉通过的字段
						validFieldKeys.forEach((fieldName) => {
							delete _invalidFields.value[fieldName];
						});
						// 显示未通过字段的错误
						showError(errors, fields);
						reject(false);
					}

					// 验证通过
					else {
						try {
							fieldNames.forEach((fieldName) => {
								delete _invalidFields.value[fieldName];
							});
						} catch (error) {}
						resolve(true);
					}
				})
				.catch(() => {});
		});
	}

	// 提示错误
	function showError(errors, fields) {
		// 不提示
		if (_props?.errorMode === "none") {
			_invalidFields.value = {};
			return;
		}

		_invalidFields.value = {
			..._invalidFields.value,
			...fields
		};

		// message: 在下方提示
		if (_props?.errorMode === "message") {
			return;
		}

		// toast: 弹出提示
		if (_props?.errorMode === "toast") {
			// 只弹窗提示第一个错误
			let firstError = errors?.[0];

			// 弹窗提示
			if (firstError) {
				uni.showToast({
					title: firstError?.message || "验证未通过",
					icon: "none"
				});
			}

			return;
		}
	}

	// 重置
	function reset() {
		for (const key in _props.model) {
			if (isPlainObject(_props.model[key])) {
				resetObject(_props.model[key]);
			} else {
				_props.model[key] = null;
			}
		}
		_invalidFields.value = {};
	}

	// 将对象属性值全部设置为null
	function resetObject(obj) {
		// 遍历对象属性
		for (const key in obj) {
			// 设置属性值为null
			obj[key] = null;
		}
	}

	// -------------------------------------------------------------------------------- Provides
	// 将表单数据提供给子组件
	provide(
		"PureFormModel",
		computed(() => _props.model)
	);

	// 将表单最终的验证规则提供给子组件
	provide(
		"PureFormRules",
		computed(() => _finalRules.value)
	);

	// 将未验证通过的字段提供给子组件
	provide(
		"PureFormInvalidFields",
		computed(() => _invalidFields.value)
	);

	// 将表单标签位置提供给子组件
	provide(
		"PureFormLabelPosition",
		computed(() => _props.labelPosition)
	);

	// 将必填符号提供给子组件
	provide(
		"PureFormRequiredSymbol",
		computed(() => _props.requiredSymbol)
	);

	// 将错误提示模式提供给子组件
	provide(
		"PureFormErrorMode",
		computed(() => _props.errorMode)
	);

	// 将图标配置提供给子组件
	provide(
		"PureFormIconOpts",
		computed(() => _props.iconOpts)
	);

	// 将是否显示右侧箭头提供给子组件
	provide(
		"PureFormShowArrow",
		computed(() => _props.showArrow)
	);

	// 将右侧箭头图标名称提供给子组件
	provide(
		"PureFormArrowIconName",
		computed(() => _props.arrowIconName)
	);

	// 将右侧箭头图标配置提供给子组件
	provide(
		"PureFormArrowIconOpts",
		computed(() => _props.arrowIconOpts)
	);

	// 将 "更新字段的验证规则" 方法提供给子组件
	provide("PureFormUpdatePureFormRules", updatePureFormRules);

	// 将 "单字段验证" 方法提供给子组件
	provide("PureFormValidateField", validateField);

	// 将 "内容对齐方式" 提供给子组件
	provide(
		"PureFormContentAlign",
		computed(() => _props.contentAlign)
	);

	// 将 "提示一直显示" 提供给子组件
	provide(
		"PureFormAlwaysTips",
		computed(() => _props.alwaysTips)
	);

	// 对外暴漏的属性和方法
	defineExpose({
		validate,
		validateField,
		validateFields,
		reset
	});
</script>

<style scoped lang="scss">
	@import "./style.scss";
</style>
